﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace GenerateAdminPage.Classes.Helpers
{
    #region USING
    using GenerateAdminPage.Classes.DBStructure;
    using GenerateAdminPage.Classes.Base;
    using GenerateAdminPage.Classes.Models;
    using GenerateAdminPage.Classes.Views;
    using GenerateAdminPage.Classes.FrmClasses;
    #endregion

    public class AdminCore
    {
        public string BasePath { get; set; }
        public DataBase DB { get; set; }

        public void InitPaths()
        {
            DataContext.Instance.DataTextProvider.InputPath = BasePath + @"\\Input\\DB.xml";
            DataContext.Instance.DataTextProvider.OutputRepositoriesPath = BasePath + @"\\Output\\Repositories\\";
            DataContext.Instance.DataTextProvider.OutputViewModelsPath = BasePath + @"\\Output\\Models\\";
            DataContext.Instance.DataTextProvider.OutputViewsPath = BasePath + @"\\Output\\MainManagers\\";
        }

        public void Generate()
        {
            try
            {
                InitPaths();

                if (DataContext.Instance.DataTextProvider.LoadDBInfo())
                {
                    GlobalVariables.Logger.Info("Load DB info successfully");
                    DataContext.Instance.CreateConnection();
                    DB = new DataBase();
                    DataContext.Instance.InitDB(DB);
                    GlobalVariables.Logger.Info("Init DB successfully");
                    DataContext.Instance.SetForeignKey(DB);
                    GlobalVariables.Logger.Info("Set ForeignKeys successfully");
                    GenerateOutput(DB);
                    GlobalVariables.Logger.Info("Generated");
                }
                else
                {
                    GlobalVariables.Logger.Error("Cannot load DB info");
                    throw new Exception("Cannot load DB info");
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
                throw new Exception(ex.Message);
            }
        }

        public void GenerateOutput(DataBase DB)
        {
            DeleteOldFiles();
            GenerateRepositories(DB);
            GenerateOverrideMethods(DB);
            GenerateResources(DB);
            GenerateDesigners(DB);
            GenerateFrmClasses(DB);
            DeleteTrashFiles();
        }

        public void GenerateOverrideMethods(DataBase DB)
        {
            try
            {
                var END = Environment.NewLine;
                StringBuilder Result = new StringBuilder();
                var path = "";

                Result.AppendLine("namespace " + GlobalVariables.g_sNameSpace + ".Models");
                Result.AppendLine("{");

                for (int i = 0; i < DB.Tables.Count; i++)
                {
                    if (DB.Tables[i].Name != "sysdiagrams")
                    {
                        Result.Append(OverrideMethod(DB.Tables[i]));
                        GlobalVariables.Logger.Info("Generated all Override methods of table " + DB.Tables[i].Name);
                    }
                }
                Result.AppendLine("}");

                path = DataContext.Instance.DataTextProvider.OutputViewModelsPath + "OverrideMethods.cs";
                DataContext.Instance.DataTextProvider.WriteData(Result.ToString(), path);
                GlobalVariables.Logger.Info("Generated all Override methods");
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
            }
        }

        public string OverrideMethod(Table _tbl)
        {
            var TAB = "\t";
            var TAB2 = "\t\t";
            var TAB3 = "\t\t\t";
            var END = Environment.NewLine;
            var attr = Utils.GetStrAttributeStartWithTen(_tbl);
            if (attr == "")
                return "";
            StringBuilder Result = new StringBuilder();
            Result.AppendLine(TAB + "public partial class " + _tbl.Name);
            Result.AppendLine(TAB + "{");
            Result.AppendLine(TAB2 + "public override string ToString()");
            Result.AppendLine(TAB2 + "{");
            Result.AppendLine(TAB3 + "return " + attr + ";");
            Result.AppendLine(TAB2 + "}");
            Result.AppendLine(TAB + "}");
            return Result.ToString();
        }

        public void GenerateResources(DataBase DB)
        {
            string oldPath = BasePath + @"\\Input\\SingleResources.resx";
            string newpath = DataContext.Instance.DataTextProvider.OutputViewsPath;
            try
            {
                for (int i = 0; i < DB.Tables.Count; i++)
                {
                    if (DB.Tables[i].Name != "sysdiagrams")
                    {
                        if (GlobalVariables.g_colComplex.Keys.Contains(DB.Tables[i].Name))
                        {
                            Table manyTbl = Utils.GetTableByName(DB, GlobalVariables.g_colComplex[DB.Tables[i].Name]);
                            GenerateResource(oldPath, newpath, "FrmLap" + DB.Tables[i].Name);
                            // Then create resources for frmQuanLy
                            GenerateResource(oldPath, newpath, "FrmQuanLy" + DB.Tables[i].Name);
                            if (manyTbl != null)
                            {
                                GenerateResource(oldPath, newpath, "FrmCapNhat" + manyTbl.Name);
                            }
                        }
                        else if (GlobalVariables.g_colSingle.Contains(DB.Tables[i].Name))
                        {
                            GenerateResource(oldPath, newpath, "FrmQuanLy" + DB.Tables[i].Name);
                        }
                    }
                }
                GlobalVariables.Logger.Info("Generated all resources");
            }
            catch (Exception ex)
            {
                GlobalVariables.Logger.Info(ex.Message);
            }
        }

        public void GenerateResource(string oldPath, string newpath, string newFileName)
        {
            FileInfo f1 = new FileInfo(oldPath);
            if (f1.Exists)
            {
                if (!Directory.Exists(newpath))
                {
                    Directory.CreateDirectory(newpath);
                }
                f1.CopyTo(string.Format("{0}{1}{2}", newpath, newFileName, f1.Extension));
                GlobalVariables.Logger.Info("Generated resource for " + newFileName);
            }
        }

        public void GenerateDesigners(DataBase DB)
        {
            try
            {
                string path = "";
                Table manyTbl;

                for (int i = 0; i < DB.Tables.Count; i++)
                {
                    if (DB.Tables[i].Name != "sysdiagrams")
                    {
                        manyTbl = null;
                        if (GlobalVariables.g_colComplex.Keys.Contains(DB.Tables[i].Name))
                        {
                            manyTbl = Utils.GetTableByName(DB, GlobalVariables.g_colComplex[DB.Tables[i].Name]);

                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmLap" + DB.Tables[i].Name + ".designer.cs";
                            GenerateDesigner(DB.Tables[i], null, path, GenerateType.COMPLEX);

                            // Then create resources for frmQuanLy
                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmQuanLy" + DB.Tables[i].Name + ".designer.cs";
                            GenerateDesigner(DB.Tables[i], null, path, GenerateType.SELECT_MANY_FOR_ONE);

                            if (manyTbl != null)
                            {
                                path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmCapNhat" + manyTbl.Name + ".designer.cs";
                                GenerateDesigner(DB.Tables[i], manyTbl, path, GenerateType.ONE_TO_MANY);
                            }
                        }
                        else if (GlobalVariables.g_colSingle.Contains(DB.Tables[i].Name))
                        {
                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmQuanLy" + DB.Tables[i].Name + ".designer.cs";
                            GenerateDesigner(DB.Tables[i], null, path, GenerateType.SINGLE);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
            }
        }

        public void GenerateDesigner(Table tblOne, Table tblMany, string path, GenerateType type)
        {
             try
             {
                 IBase _rep = AbstractViews.SelectGenerateType(tblOne, tblMany, type);
                 _rep.InitClassGenerate(DB, tblOne, tblMany);
                 string result = _rep.GenerateNameSpace("MainManagers");
                 DataContext.Instance.DataTextProvider.WriteData(result, path);
                 GlobalVariables.Logger.Info("Generated all designer of table " + tblOne.Name);
             }
             catch (Exception ex)
             {
                 if (ex.InnerException != null)
                 {
                     GlobalVariables.Logger.Error(ex.InnerException.Message);
                 }
                 else
                 {
                     GlobalVariables.Logger.Error(ex.Message);
                 }
             }
        }

        public void GenerateRepositories(DataBase DB)
        {
            try
            {
                IBase _rep = null;
                var Result = string.Empty;
                var path = "";
                for (int i = 0; i < DB.Tables.Count; i++)
                {
                    if (DB.Tables[i].Name != "sysdiagrams")
                    {
                        _rep = Repository.SelectGenerateType(DB.Tables[i], null);
                        _rep.InitClassGenerate(DB, DB.Tables[i], null);
                        Result = _rep.GenerateNameSpace("Repositories");

                        path = DataContext.Instance.DataTextProvider.OutputRepositoriesPath + DB.Tables[i].Name + "Repository.cs";
                        DataContext.Instance.DataTextProvider.WriteData(Result, path);
                        GlobalVariables.Logger.Info("Generated repository of table " + DB.Tables[i].Name);
                    }
                }
                GlobalVariables.Logger.Info("Generated all repositories");
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
                throw new Exception(ex.Message);
            }
        }

        public void GenerateFrmClasses(DataBase DB)
        {
            try
            {
                string path = "";
                Table manyTbl;

                for (int i = 0; i < DB.Tables.Count; i++)
                {
                    if (DB.Tables[i].Name != "sysdiagrams")
                    {
                        manyTbl = null;

                        if (GlobalVariables.g_colComplex.Keys.Contains(DB.Tables[i].Name))
                        {
                            manyTbl = Utils.GetTableByName(DB, GlobalVariables.g_colComplex[DB.Tables[i].Name]);

                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmLap" + DB.Tables[i].Name + ".cs";
                            GenerateFrmClass(DB.Tables[i], manyTbl, path, GenerateType.COMPLEX);

                            // Then create resources for frmQuanLy
                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmQuanLy" + DB.Tables[i].Name + ".cs";
                            GenerateFrmClass(DB.Tables[i], null, path, GenerateType.SELECT_MANY_FOR_ONE);

                            if (manyTbl != null)
                            {
                                path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmCapNhat" + manyTbl.Name + ".cs";
                                GenerateFrmClass(DB.Tables[i], manyTbl, path, GenerateType.ONE_TO_MANY);
                            }
                        }
                        else if (GlobalVariables.g_colSingle.Contains(DB.Tables[i].Name))
                        {
                            path = DataContext.Instance.DataTextProvider.OutputViewsPath + "FrmQuanLy" + DB.Tables[i].Name + ".cs";
                            GenerateFrmClass(DB.Tables[i], null, path, GenerateType.SINGLE);
                        }
                    }
                }
                GlobalVariables.Logger.Info("Generated all class forms");
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public void GenerateFrmClass(Table tblOne, Table tblMany, string path, GenerateType type)
        {
            try
            {
                IBase _rep = AbstractFrmClass.SelectGenerateType(tblOne, tblMany, type);
                _rep.InitClassGenerate(DB, tblOne, tblMany);
                string result = _rep.GenerateNameSpace("MainManagers");
                DataContext.Instance.DataTextProvider.WriteData(result, path);
                GlobalVariables.Logger.Info("Generated all form class of table " + tblOne.Name);
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
            }
        }

        public void DeleteOldFiles()
        {
            try
            {
                var viewmodelPath = DataContext.Instance.DataTextProvider.OutputViewModelsPath;
                var repPath = DataContext.Instance.DataTextProvider.OutputRepositoriesPath;
                var viewPath = DataContext.Instance.DataTextProvider.OutputViewsPath;

                if (System.IO.Directory.Exists(viewmodelPath))
                {
                    try
                    {
                        string[] filePaths = Directory.GetFiles(viewmodelPath);
                        foreach (string filePath in filePaths)
                        {
                            System.IO.File.Delete(filePath);
                        }
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }

                if (System.IO.Directory.Exists(repPath))
                {
                    try
                    {
                        string[] filePaths = Directory.GetFiles(repPath);
                        foreach (string filePath in filePaths)
                        {
                            System.IO.File.Delete(filePath);
                        }
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }

                if (System.IO.Directory.Exists(viewPath))
                {
                    try
                    {
                        string[] filePaths = Directory.GetFiles(viewPath);
                        foreach (string filePath in filePaths)
                        {
                            System.IO.File.Delete(filePath);
                        }
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }
                GlobalVariables.Logger.Info("Delete old files");
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
            }
        }

        public void DeleteTrashFiles()
        {
            try
            {
                var viewmodelPath = DataContext.Instance.DataTextProvider.OutputViewModelsPath + "\\trash.xml";
                var repPath = DataContext.Instance.DataTextProvider.OutputRepositoriesPath + "\\trash.xml";
                var viewPath = DataContext.Instance.DataTextProvider.OutputViewsPath + "\\trash.xml";

                if (System.IO.File.Exists(viewmodelPath))
                {
                    try
                    {
                        System.IO.File.Delete(viewmodelPath);
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }

                if (System.IO.File.Exists(repPath))
                {
                    try
                    {
                        System.IO.File.Delete(repPath);
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }

                if (System.IO.File.Exists(viewPath))
                {
                    try
                    {
                        System.IO.File.Delete(viewPath);
                    }
                    catch (System.IO.IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            GlobalVariables.Logger.Error(ex.InnerException.Message);
                        }
                        else
                        {
                            GlobalVariables.Logger.Error(ex.Message);
                        }
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    GlobalVariables.Logger.Error(ex.InnerException.Message);
                }
                else
                {
                    GlobalVariables.Logger.Error(ex.Message);
                }
            }
        }

        public Table GetNguoiDungBaseInfo()
        {
            for (int i = 0; i < DB.Tables.Count; i++)
            {
                if (DB.Tables[i].Name == "aspnet_Users")
                    return DB.Tables[i];
            }

            return null;
        }
    }
}
